// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Collections.ObjectModel;
using Microsoft.TeamFoundation.Migration.Toolkit;
using Microsoft.TeamFoundation.Migration.Toolkit.VC;
using System.Threading;

namespace Microsoft.Vsts.Rangers.Migration.TfsToTfs
{
    public class Session : VersionControlSession
    {










        private ChangeGroupingMananger m_forwardMigrationManager;
        private ChangeGroupingMananger m_backwardMigrationManager;
        private Collection<VersionControlMapping> m_reversedMappings;
        Thread m_analysisThread;
        Thread m_migrationThread;
        private object m_stateLock = new object();
        private bool m_forwardAnalysisComplete;

        private bool forwardAnalysisComplete
        {
            get
            {
                lock (m_stateLock)
                {
                    return m_forwardAnalysisComplete;
                }
            }
            set
            {
                Debug.Assert(value);

                lock (m_stateLock)
                {
                    m_forwardAnalysisComplete = value;
                }
            }
        }

        private bool m_forwardMigrationComplete;
        private bool forwardMigrationComplete
        {
            get
            {
                lock (m_stateLock)
                {
                    return m_forwardMigrationComplete;
                }
            }
            set
            {
                Debug.Assert(value);

                lock (m_stateLock)
                {
                    m_forwardMigrationComplete = value;
                }
            }
        }



        private bool m_backwardAnalysisComplete;
        private bool backwardAnalysisComplete
        {
            get
            {
                lock (m_stateLock)
                {
                    return m_backwardAnalysisComplete;
                }
            }
            set
            {
                Debug.Assert(value);

                lock (m_stateLock)
                {
                    m_backwardAnalysisComplete = value;
                }
            }
        }

        private static void shutdownThread(Thread thread)
        {
            if (thread != null)
            {
                try
                {
                    thread.Abort();
                }
                catch (Exception e)
                {
                    TraceManager.TraceException(e);
                    throw;
                }
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void AnalysisThread()
        {
            Thread.CurrentThread.Name = ResourceStrings.AnalysisThreadName;

            try
            {
                if (m_forwardMigrationManager != null)
                {
                    TfsToTfsAnalysisEngine forwardAnalysis = new TfsToTfsAnalysisEngine(this, m_forwardMigrationManager);
                    OnBeforeAnalysis(new VersionControlEventArgs(ResourceStrings.ForwardAnalysisStarted, SystemType.Other));
                    forwardAnalysis.Run();
                    OnAnalysisComplete(new VersionControlEventArgs(ResourceStrings.ForwardAnalysisCompleted, SystemType.Other));
                }
                forwardAnalysisComplete = true;
                if (m_backwardMigrationManager != null)
                {
                    TfsToTfsAnalysisEngine backwardAnalysis = new TfsToTfsAnalysisEngine(this, m_backwardMigrationManager);
                    OnBeforeAnalysis(new VersionControlEventArgs(ResourceStrings.BackwardAnalysisStarted, SystemType.Tfs));
                    backwardAnalysis.Run();
                    OnAnalysisComplete(new VersionControlEventArgs(ResourceStrings.BackwardAnalysisCompleted, SystemType.Tfs));
                }
                backwardAnalysisComplete = true;
            }
            catch (Exception ex)
            {
                TraceManager.TraceException(ex);
                Abort();
            }
        }

        private void MigrationThread()
        {
            Thread.CurrentThread.Name = ResourceStrings.MigrationThreadName;
            try
            {
                if (m_forwardMigrationManager != null)
                {
                    TfsToTfsMigrationEngine forwardMigrate = new TfsToTfsMigrationEngine(this, m_forwardMigrationManager);
                    while (!forwardAnalysisComplete)
                    {
                        ThrowIfAborted();
                        Thread.Sleep(1000);
                        forwardMigrate.Run();
                    }

                    // and then once more to make sure we got it all
                    forwardMigrate.Run();
                    OnMigrationComplete(new VersionControlEventArgs(ResourceStrings.ForwardMigrationCompleted, SystemType.Other));
                }
                forwardMigrationComplete = true;

                if (m_backwardMigrationManager != null)
                {
                    TfsToTfsMigrationEngine backwardMigrate = new TfsToTfsMigrationEngine(this, m_backwardMigrationManager);
                    while (!backwardAnalysisComplete)
                    {
                        ThrowIfAborted();
                        Thread.Sleep(1000);
                        backwardMigrate.Run();
                    }
                    // and then once more to make sure we got it all
                    backwardMigrate.Run();
                    OnMigrationComplete(new VersionControlEventArgs(ResourceStrings.BackwardMigrationCompleted, SystemType.Tfs));
                }
                Complete();
            }
            catch (Exception ex)
            {
                TraceManager.TraceException(ex);
                SystemType sourceSystem = (forwardMigrationComplete) ? SystemType.Tfs : SystemType.Other;
                OnMigrationError(new VersionControlEventArgs(ex.Message, sourceSystem));
                Abort();
            }
        }

        public override void Abort()
        {
            base.Abort();

            shutdownThread(m_analysisThread);
            shutdownThread(m_migrationThread);
        }

        /// <summary>
        /// Target of the session. Returns target for forward migration and source for backward migration 
        /// </summary>
        public override TfsVersionControlTargetEndpoint Target
        {
            get
            {
                if (isForwardMigration)
                    return base.Target;
                else
                    return (TfsVersionControlTargetEndpoint)base.Source;
            }
        }

        /// <summary>
        /// Source of the session. Returns source for forward migration and target for backward migration 
        /// </summary>
        public override IVersionControlEndpoint Source
        {
            get
            {
                if (isForwardMigration)
                    return base.Source;
                else
                    return base.Target;
            }
        }

        /// <summary>
        /// Mappings for VC session, returns reversed mappings for backward migration
        /// </summary>
        public override Collection<VersionControlMapping> Mappings
        {
            get
            {
                if (isForwardMigration)
                    return base.Mappings;
                else
                    return RevsersedMappings;
            }
        }

        private Collection<VersionControlMapping> RevsersedMappings
        {
            get
            {
                if (m_reversedMappings == null)
                {
                    m_reversedMappings = Util.ReverseVersionControlMappings(base.Mappings);
                }
                return m_reversedMappings;
            }
        }
        /// <summary>
        /// For the following cases, we are in backward direction, source and target need to reversed
        /// 1. we are in analysis thread and forward analysis is finished
        /// 2. we are in migration thread and forward migration is finished 
        /// </summary>
        internal bool isForwardMigration
        {
            get
            {
                if ((m_analysisThread != null) && (Thread.CurrentThread.ManagedThreadId == m_analysisThread.ManagedThreadId))
                {
                    if (forwardAnalysisComplete)
                        return false;
                    else
                        return true;
                }
                else if ((m_migrationThread != null) && (Thread.CurrentThread.ManagedThreadId == m_migrationThread.ManagedThreadId))
                {
                    if (forwardMigrationComplete)
                        return false;
                    else
                        return true;
                }
                else
                    return true;
            }
        }

        protected override void DoSynchronize(SystemType primarySystem)
        {
            if (primarySystem == SystemType.Other)
            {
                // One way source to tfs
                m_forwardMigrationManager = new SqlChangeGroupingMananger(
                    new TfsMigrationItemSerialzier(),
                    new TfsMigrationItemSerialzier(),
                    this,
                    MigrationDirection.SourceToTfs);
                m_backwardMigrationManager = null;
            }
            else
            {
                // One way tfs to source
                m_forwardMigrationManager = null;
                m_backwardMigrationManager = new SqlChangeGroupingMananger(
                    new TfsMigrationItemSerialzier(),
                    new TfsMigrationItemSerialzier(),
                    this,
                    MigrationDirection.TfsToSource);
            }
            startSyncThreads();
        }

        private void startSyncThreads()
        {
            m_forwardAnalysisComplete = false;
            m_forwardMigrationComplete = false;
            m_backwardAnalysisComplete = false;

            m_analysisThread = new Thread(AnalysisThread);
            m_analysisThread.Start();

            m_migrationThread = new Thread(MigrationThread);
            m_migrationThread.Start();
        }


        protected override void DoSynchronizeFull()
        {
            m_forwardMigrationManager = new SqlChangeGroupingMananger(
                new TfsMigrationItemSerialzier(),
                new TfsMigrationItemSerialzier(),
                this,
                MigrationDirection.SourceToTfs);

            m_backwardMigrationManager = new SqlChangeGroupingMananger(
                new TfsMigrationItemSerialzier(),
                new TfsMigrationItemSerialzier(),
                this,
                MigrationDirection.TfsToSource);
            startSyncThreads();
        }
    }
}
